package com.wiwf.model.magicapi.redis.service;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.ssssssss.magicapi.core.resource.KeyValueResource;
import org.ssssssss.magicapi.core.resource.Resource;

public class RedisResource extends KeyValueResource {
    private static final Logger logger = LoggerFactory.getLogger(RedisResource.class);
    private final StringRedisTemplate redisTemplate;
    private final Map<String, String> cachedContent;

    public RedisResource(StringRedisTemplate redisTemplate, String path, boolean readonly, RedisResource parent) {
        super(":", path, readonly, parent);
        this.cachedContent = new ConcurrentHashMap<>();
        this.redisTemplate = redisTemplate;
    }

    public RedisResource(StringRedisTemplate redisTemplate, String path, boolean readonly) {
        this(redisTemplate, path, readonly, null);
    }

    public void readAll() {
        List<String> keys = new ArrayList<>(this.keys());
        List<String> values = this.redisTemplate.opsForValue().multiGet(keys);
        this.cachedContent.entrySet().removeIf((entry) -> {
            return ((String)entry.getKey()).startsWith(this.path);
        });
        if (values != null) {
            int i = 0;

            for(int size = keys.size(); i < size; ++i) {
                this.cachedContent.put((String)keys.get(i), (String)values.get(i));
            }
        }

    }

    public byte[] read() {
        String value = (String)this.cachedContent.get(this.path);
        if (value == null) {
            value = (String)this.redisTemplate.opsForValue().get(this.path);
            if (value != null) {
                this.cachedContent.put(this.path, value);
            }
        }

        return value == null ? new byte[0] : value.getBytes(StandardCharsets.UTF_8);
    }

    public boolean write(String content) {
        this.redisTemplate.opsForValue().set(this.path, content);
        this.cachedContent.put(this.path, content);
        return true;
    }

    protected boolean renameTo(Map<String, String> renameKeys) {
        StringRedisTemplate var10001 = this.redisTemplate;
        Objects.requireNonNull(var10001);
        renameKeys.forEach(var10001::rename);
        renameKeys.forEach((oldKey, newKey) -> {
            this.cachedContent.put(newKey, (String)this.cachedContent.remove(oldKey));
        });
        return true;
    }

    public boolean exists() {
        return this.cachedContent.get(this.path) != null || Boolean.TRUE.equals(this.redisTemplate.hasKey(this.path));
    }

    protected boolean deleteByKey(String key) {
        if (Boolean.TRUE.equals(this.redisTemplate.delete(key))) {
            this.cachedContent.remove(key);
            return true;
        } else {
            return false;
        }
    }

    protected Function<String, Resource> mappedFunction() {
        return (it) -> {
            return new RedisResource(this.redisTemplate, it, this.readonly, this);
        };
    }

    protected Set<String> keys() {
        Set<String> keys = this.redisTemplate.execute((RedisCallback<Set<String>>) (connection) -> {
            ScanOptions options = ScanOptions.scanOptions().count(Long.MAX_VALUE).match((this.isDirectory() ? this.path : this.path + this.separator) + "*").build();
            Set<String> returnKeys = new HashSet<>();

            try {
                Cursor<byte[]> cursor = connection.scan(options);

                try {
                    while(cursor.hasNext()) {
                        returnKeys.add(new String((byte[])cursor.next()));
                    }
                } catch (Throwable var8) {
                    try {
                        cursor.close();
                    } catch (Throwable var7) {
                        var8.addSuppressed(var7);
                    }

                    throw var8;
                }

                cursor.close();
            } catch (Exception var9) {
                logger.error("扫描key出错", var9);
            }

            return returnKeys;
        });
        return keys == null ? Collections.emptySet() : keys;
    }

    public String toString() {
        return String.format("redis://%s", this.getAbsolutePath());
    }
}
